﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Windows.Interactivity;

namespace DeepZoom.Behaviors
{
    public class DeepZoomMouse : Behavior<MultiScaleImage>
    {

        public static readonly DependencyProperty ZoomFactorProperty =
            DependencyProperty.Register("ZoomFactor", typeof(double), typeof(DeepZoomMouse), new PropertyMetadata(null));
        public static readonly DependencyProperty MinViewportWidthrProperty =
           DependencyProperty.Register("MinViewportWidth", typeof(double), typeof(DeepZoomMouse), new PropertyMetadata(null));
        public static readonly DependencyProperty MaxViewportWidthProperty =
           DependencyProperty.Register("MaxViewportWidth", typeof(double), typeof(DeepZoomMouse), new PropertyMetadata(null));

        bool pressed = false;
        Point pressedPoint;
        Point pressedOrigin;

        public DeepZoomMouse()
        {
            ZoomFactor = 0.15;
            MinViewportWidth = MaxViewportWidth = 0;
        }


        [Category("Misc")]
        [DefaultValue(0.15)]
        public double ZoomFactor { get; set; }

        [Category("Misc")]
        [DefaultValue(0)]
        public double MinViewportWidth { get; set; }

        [Category("Misc")]
        [DefaultValue(0)]
        public double MaxViewportWidth { get; set; }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.MouseLeftButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
            AssociatedObject.MouseLeftButtonUp += new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
            AssociatedObject.MouseMove += new MouseEventHandler(AssociatedObject_MouseMove);
            AssociatedObject.MouseWheel += new MouseWheelEventHandler(AssociatedObject_MouseWheel);
        }


        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.MouseLeftButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
            AssociatedObject.MouseLeftButtonUp -= new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonUp);
            AssociatedObject.MouseMove -= new MouseEventHandler(AssociatedObject_MouseMove);
            AssociatedObject.MouseWheel -= new MouseWheelEventHandler(AssociatedObject_MouseWheel);
        }

        void AssociatedObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (pressed)
            {
                pressed = false;
                DeepZoomBounds.CheckBounds(AssociatedObject);
                AssociatedObject.ReleaseMouseCapture();
            }
        }

        void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Point pMouse = e.GetPosition(AssociatedObject);
            Point lMouse = AssociatedObject.ElementToLogicalPoint(pMouse);

            if (DeepZoomBounds.PointInRange(lMouse, AssociatedObject))
            {
                pressed = true;
                pressedPoint = pMouse;
                pressedOrigin = AssociatedObject.ViewportOrigin;
                AssociatedObject.CaptureMouse();
            }
        }

        void AssociatedObject_MouseMove(object sender, MouseEventArgs e)
        {
            if (pressed)
            {
                Point pMouse = e.GetPosition(AssociatedObject);
                AssociatedObject.UseSprings = false;
                double ratio = AssociatedObject.ViewportWidth / AssociatedObject.ActualWidth;
                AssociatedObject.ViewportOrigin = new Point()
                {
                    X = pressedOrigin.X - (pMouse.X - pressedPoint.X) * ratio,
                    Y = pressedOrigin.Y - (pMouse.Y - pressedPoint.Y) * ratio
                };
            }
        }

        void AssociatedObject_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            Point pMouse = e.GetPosition(AssociatedObject);
            Point lMouse = AssociatedObject.ElementToLogicalPoint(pMouse);
            if (DeepZoomBounds.PointInRange(lMouse, AssociatedObject))
            {
                AssociatedObject.UseSprings = true;
                double factor = 1;
                if (e.Delta > 0)
                    factor = 1 + ZoomFactor;
                else
                    factor = 1 / (1 + ZoomFactor);

                double lastViewportWidth = AssociatedObject.ViewportWidth;
                Point lastViewportOrigin = AssociatedObject.ViewportOrigin;
                double newViewportWidth = lastViewportWidth * factor;
                if (MinViewportWidth != 0 && newViewportWidth < MinViewportWidth)
                    newViewportWidth = MinViewportWidth;
                if (MaxViewportWidth != 0 && newViewportWidth > MaxViewportWidth)
                    newViewportWidth = MaxViewportWidth;
                Point newViewportOrigin = new Point()
                {
                    X = lMouse.X - (lMouse.X - lastViewportOrigin.X) * newViewportWidth / lastViewportWidth,
                    Y = lMouse.Y - (lMouse.Y - lastViewportOrigin.Y) * newViewportWidth / lastViewportWidth
                };

                AssociatedObject.UseSprings = false;
                AssociatedObject.ViewportWidth = newViewportWidth;
                AssociatedObject.ViewportOrigin = newViewportOrigin;

                //factor = newWitdh / AssociatedObject.ViewportWidth;
                //AssociatedObject.ZoomAboutLogicalPoint(factor, lMouse.X, lMouse.Y);
                    
                //if (e.Delta > 0) 
                //    AssociatedObject.ZoomAboutLogicalPoint(1 + ZoomFactor, lMouse.X, lMouse.Y);
                //else
                //    AssociatedObject.ZoomAboutLogicalPoint(1 / (1 + ZoomFactor), lMouse.X, lMouse.Y);
            }
        }

    }
}
